package br.com.news.database.daos;

import java.util.List;

import javax.inject.Named;

import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.Transformers;
import org.springframework.util.StringUtils;

import br.com.news.database.daos.interfaces.INoticiaDao;
import br.com.news.database.entities.NoticiaEntity;
import br.com.news.database.exception.DataBaseException;
import br.com.news.database.utils.GenericDao;

@Named
public class NoticiaDao extends GenericDao<NoticiaEntity, Long> implements INoticiaDao{

	public boolean existeNoticia(NoticiaEntity noticia) {
		Criteria criteria = getSession().createCriteria(NoticiaEntity.class);
		criteria.add(Restrictions.eq("titulo", noticia.getTitulo()));
		return criteria.list().size() >0 ? true : false;
	}
	
	private Criteria simpleObject(Criteria criteria) {
		return criteria.setProjection(Projections.projectionList()
				.add(Projections.property("idNoticia"), "idNoticia")
				.add(Projections.property("categoria"), "categoria")
				.add(Projections.property("usuario"), "usuario")
				.add(Projections.property("fonte"), "fonte")
				.add(Projections.property("autor"), "autor")
				.add(Projections.property("dataCriacao"), "dataCriacao")
				.add(Projections.property("dataNoticia"), "dataNoticia")
				.add(Projections.property("status"), "status")
				.add(Projections.property("titulo"), "titulo")
				.add(Projections.property("subTitulo"), "subTitulo")
				.add(Projections.property("url"), "url"))
				.setResultTransformer(Transformers.aliasToBean(NoticiaEntity.class));
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<NoticiaEntity> getUltimasNoticias(int qntNoticias,
			long idCategoria) throws DataBaseException {
		try {
			Criteria criteria = getSession().createCriteria(NoticiaEntity.class);
			criteria.setFetchMode("categoria", FetchMode.JOIN);
			criteria = simpleObject(criteria);
			criteria.add(Restrictions.eq("categoria.idCategoria", idCategoria));
			criteria.add(Restrictions.eq("status", true));
			criteria.addOrder(Order.desc("idNoticia"));
			criteria.setMaxResults(qntNoticias);
			return criteria.list();
		} catch (Exception e) {
			throw new DataBaseException("Falha ao buscar ultimas noticias!", e);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<NoticiaEntity> getNoticiasAnteriores(int qntNoticias,
			long idNoticia, long idCategoria) throws DataBaseException {
		try {
			Criteria criteria = getSession().createCriteria(NoticiaEntity.class);
			criteria.setFetchMode("categoria", FetchMode.JOIN);
			criteria = simpleObject(criteria);
			criteria.add(Restrictions.eq("categoria.idCategoria", idCategoria));
			criteria.add(Restrictions.lt("idNoticia", idNoticia));
			criteria.add(Restrictions.eq("status", true));
			criteria.addOrder(Order.desc("idNoticia"));
			criteria.setMaxResults(qntNoticias);
			return criteria.list();
		} catch (Exception e) {
			throw new DataBaseException(String.format("Falha ao buscar noticias anteriores a %d!",idNoticia), e);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<NoticiaEntity> findLastNews(long idNoticia, long idCategoria) 
			throws DataBaseException {
		try {
			Criteria criteria = getSession().createCriteria(NoticiaEntity.class);
			criteria = simpleObject(criteria);
			criteria.add(Restrictions.eq("categoria.idCategoria", idCategoria));
			criteria.add(Restrictions.gt("idNoticia", idNoticia));
			criteria.add(Restrictions.eq("status", true));
			criteria.addOrder(Order.asc("idNoticia"));
			return criteria.list();
		} catch (Exception e) {
			throw new DataBaseException(String.format("Falha ao buscar noticias anteriores a %d!",idNoticia), e);
		}
	}
	
	@Override
	public NoticiaEntity findNoticiaById(Long id) {
		Criteria criteria = getSession().createCriteria(NoticiaEntity.class);
		criteria.add(Restrictions.eq("idNoticia", id));
		return (NoticiaEntity) criteria.list().get(0);
	}
	
	@Override
	public Long quantidadePaginas(long idCategoria) {
		if (idCategoria != 0) {
			return (Long) getSession().createQuery("select count(n.idNoticia) from NoticiaEntity n where n.categoria.idCategoria = "+idCategoria).list().get(0);
		}
		return (Long) getSession().createQuery("select count(n.idNoticia) from NoticiaEntity n").list().get(0);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<NoticiaEntity> findNoticiasPorPagina(int linha,Long idCategoria,int quantidade) {
		Criteria criteria = getSession().createCriteria(NoticiaEntity.class);
		criteria = simpleObject(criteria);
		criteria.setFirstResult(linha).setMaxResults(quantidade);
		criteria.addOrder(Order.asc("idNoticia"));
		if (idCategoria != 0) {
			criteria.add(Restrictions.eq("categoria.idCategoria", idCategoria));
		}
		criteria.add(Restrictions.eq("status", true));
		
		return criteria.list();
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<NoticiaEntity> getUltimasNoticiasXml(int qntNoticias)
			throws DataBaseException {
		try {
			Criteria criteria = getSession().createCriteria(NoticiaEntity.class);
			criteria.setFetchMode("categoria", FetchMode.JOIN);
			criteria = simpleObject(criteria);
			criteria.addOrder(Order.desc("idNoticia"));
			criteria.add(Restrictions.eq("status", true));
			criteria.setMaxResults(qntNoticias);
			return criteria.list();
		} catch (Exception e) {
			throw new DataBaseException("Falha ao buscar ultimas noticias!");
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<NoticiaEntity> getNoticiasAnterioresXml(int qntNoticias,
			long idNoticia) throws DataBaseException {
		try {
			Criteria criteria = getSession().createCriteria(NoticiaEntity.class);
			criteria = simpleObject(criteria);
			criteria.add(Restrictions.lt("idNoticia", idNoticia));
			criteria.add(Restrictions.eq("status", true));
			criteria.addOrder(Order.asc("idNoticia"));
			criteria.setMaxResults(qntNoticias);
			return criteria.list();
		} catch (Exception e) {
			throw new DataBaseException(String.format("Falha ao buscar noticias anteriores a %d!",idNoticia));
		}
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<NoticiaEntity> buscaNoticiaPorNome(String nome) {
		Criteria criteria = getSession().createCriteria(NoticiaEntity.class);
		criteria.add(Restrictions.like("titulo",nome, MatchMode.ANYWHERE));
		return criteria.list();
	}
	
	@Override
	public NoticiaEntity findImageByIdNoticia(Long idNoticia) throws DataBaseException {
		try {
			Criteria criteria = getSession().createCriteria(NoticiaEntity.class);
			criteria.add(Restrictions.eq("idNoticia", idNoticia));
			criteria.setProjection(
					Projections.projectionList().add(Projections.property("idNoticia"), "idNoticia")
							.add(Projections.property("arquivoImagem"), "arquivoImagem")).setResultTransformer(Transformers.aliasToBean(NoticiaEntity.class));
			return (NoticiaEntity) criteria.uniqueResult();
		} catch (Exception e) {
			throw new DataBaseException(String.format("Falha ao buscar imagem da notícia %d!", idNoticia));
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<NoticiaEntity> findByExample(NoticiaEntity noticiaEntity) {
		Criteria criteria = getSession().createCriteria(NoticiaEntity.class);
		
		if (StringUtils.hasLength(noticiaEntity.getTitulo())) {
			criteria.add(Restrictions.like("titulo", noticiaEntity.getTitulo(), MatchMode.ANYWHERE));
		}
		
		if (StringUtils.hasLength(noticiaEntity.getSubTitulo())) {
			criteria.add(Restrictions.like("subTitulo", noticiaEntity.getSubTitulo(), MatchMode.ANYWHERE));
		}
		
		if (noticiaEntity.getFonte() != null && noticiaEntity.getFonte().getIdFonte() != null) {
			criteria.add(Restrictions.eq("fonte.idFonte", noticiaEntity.getFonte().getIdFonte()));
		}
		
		if (StringUtils.hasLength(noticiaEntity.getAutor())) {
			criteria.add(Restrictions.like("autor", noticiaEntity.getAutor(), MatchMode.ANYWHERE));
		}
		
		if (noticiaEntity.getDataNoticia() != null) {
			criteria.add(Restrictions.eq("dataNoticia", noticiaEntity.getDataNoticia()));
		}
		
		if (StringUtils.hasLength(noticiaEntity.getTexto())) {
			criteria.add(Restrictions.eq("texto", noticiaEntity.getTexto()));
		}
		
		criteria.add(Restrictions.eq("status", noticiaEntity.isStatus()));
		
		return criteria.list();
	}

}
